package com.moleq.network;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;

public class MGFileHander {

	private ReceiveFileThread mReceiveFileSvr;

	private int bufferSize = 1024;

	private String mInBoxPath = "";

	public class SendFileThread extends Thread {
		byte byteBuffer[] = new byte[bufferSize];
		String remoteIPString = null;
		int port;
		Socket tempSocket;
		OutputStream outSocket;
		InputStream inSocket;
		private String mfilePath;

		public SendFileThread(String remoteIPString, int port) {
			try {
				this.remoteIPString = remoteIPString;
				this.port = port;

			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}

		@Override
		public void run() {
			try {
				this.tempSocket = new Socket();
				SocketAddress socketAddress = new InetSocketAddress(this.remoteIPString, this.port);
				tempSocket.connect(socketAddress, 5000);
				System.out.println("与服务器连接成功!");

				int amount;
				if (tempSocket.isConnected()) {
					outSocket = tempSocket.getOutputStream();
					inSocket = tempSocket.getInputStream();

					writeString(outSocket, getFileInfo(mfilePath));
					sleep(500);

					String command = readString(inSocket);
					if (command.contains("ready=1")) {
						File readySendFile = new File(mfilePath);
						FileInputStream fis = new FileInputStream(readySendFile);
						System.out.println("开始发送文件...");
						while ((amount = fis.read(byteBuffer)) != -1) {
							outSocket.write(byteBuffer, 0, amount);
							System.out.println("文件发送中...");
						}
						System.out.println("Send File complete");
						fis.close();

						readySendFile.delete();
					}
				}
			} catch (Exception e) {
				System.out.println(e.toString());
				e.printStackTrace();
			} finally {
				try {
					if (tempSocket.isBound()) {
						inSocket.close();
						outSocket.close();
						tempSocket.close();
					}
				} catch (Exception ex2) {
					ex2.printStackTrace();
				}
			}

		}

		public void execute(String filePath) {
			try {
				mfilePath = filePath;
				// outFile = new RandomAccessFile(filePath, "r");

				this.start();
			} catch (Exception ex) {
				// TODO Auto-generated catch block
				ex.printStackTrace();
			}
		}
	}

	private class SaveFile2Disk extends Thread {

		private Socket _socket = null;
		private InputStream _is = null;
		private OutputStream _os = null;

		public SaveFile2Disk(Socket socket) {
			this._socket = socket;
			try {
				_is = _socket.getInputStream();
				_os = _socket.getOutputStream();
				System.out.println(socket.getInetAddress() + " is connected.");
			} catch (Exception ex) {
				// TODO: handle exception
				ex.printStackTrace();
			}
		}

		@Override
		public void run() {

			try {

				File inbox = new File(mInBoxPath);
				if (inbox.isDirectory()) {
					String command = readString(_is);

					if (command == null || !command.contains("MoleQInfo")) {
						return;
					}
					String fileName = getTagValue(command, "FileName");
					String fileSize = getTagValue(command, "FileLength");

					sleep(200);

					writeString(_os, "ready=1");

					receiveFile(_is, fileName, fileSize);
				}

			} catch (Exception ex) {
				ex.printStackTrace();
			} finally {
				if (_socket.isConnected()) {
					try {
						_is.close();
						_os.close();
						_socket.close();
					} catch (Exception ex2) {
						ex2.printStackTrace();
					}
				}
			}
		}
	}

	private String getFileInfo(String filePath) throws Exception {
		File tempFile = new File(filePath);
		String fileName = tempFile.getName();
		long fileSize = tempFile.length();
		String fileInfos;
		fileInfos = "MoleQInfo";
		fileInfos += "<FileName>" + fileName + "</FileName>";
		fileInfos += "<FileLength>" + fileSize + "</FileLength>";
		return fileInfos;
	}

	private void writeString(OutputStream os, String context) throws IOException {
		OutputStreamWriter osw = new OutputStreamWriter(os);
		BufferedWriter writer = new BufferedWriter(osw);

		writer.write(context);
		writer.flush();
	}

	private String readString(InputStream is) throws IOException {
		String result = "";

		byte[] buffer = new byte[bufferSize];

		String recBuffer = "";
		int readCount = 0;
		while ((readCount = is.read(buffer, 0, bufferSize)) > 0) {

			recBuffer += new String(buffer, 0, readCount);
			if (readCount < bufferSize) {
				System.out.println("receive end ->" + recBuffer);
				result = recBuffer;
				break;
			}
		}
		return result;
	}

	private void receiveFile(InputStream is, String fileName, String fileSize) throws Exception {

		byte byteBuffer[] = new byte[bufferSize];
		long totalCount = 0;
		int count = 0;
		long filesize = Long.valueOf(fileSize);
		BufferedInputStream bis = new BufferedInputStream(is);

		File recfile = new File(mInBoxPath, fileName + ".temp");
		FileOutputStream fos = new FileOutputStream(recfile);
		BufferedOutputStream bos = new BufferedOutputStream(fos);

		do {
			count = bis.read(byteBuffer);
			bos.write(byteBuffer, 0, count);
			totalCount += count;
		} while (totalCount < filesize);
		bos.flush();
		bos.close();

		if (recfile.exists()) {
			File newFile = new File(mInBoxPath, fileName);

			if (newFile.exists())
				newFile.delete();

			recfile.renameTo(newFile);
		}

	}

	public void sendFile(String fileName, String ipAddress, int port) {
		SendFileThread task = new SendFileThread(ipAddress, port);
		task.execute(fileName);
	}

	protected void sleep(int time) {
		try {
			Thread.sleep(time);
		} catch (InterruptedException ex) {
			// TODO Auto-generated catch block
			ex.printStackTrace();
		}
	}

	public String getTagValue(String str, String tag) {
		String result = "";
		String start, end;
		int i, j;

		if (str.equals("") || tag.equals(""))
			return result;

		start = "<" + tag + ">";
		end = "</" + tag + ">";

		i = str.indexOf(start);
		j = str.indexOf(end);
		if (i >= 0 && j >= 0) {
			result = str.substring(i + start.length(), j);
		}
		return result;
	}

	public void listen(int port) {

		release();

		mReceiveFileSvr = new ReceiveFileThread(port);
		mReceiveFileSvr.start();
	}

	public void release() {
		if (mReceiveFileSvr != null) {
			mReceiveFileSvr.release();
		}
	}

	public void setInBox(String path) {
		File inbox = new File(path);
		if (inbox.isDirectory()) {
			mInBoxPath = path;
		} else {
			mInBoxPath = "";
		}
	}

	public static void main(String[] args) {
		MGFileHander fh = new MGFileHander();
		fh.setInBox("C:\\");
		fh.listen(6600);
	}

	private class ReceiveFileThread extends Thread {
		private boolean autoRestart = false;
		private ServerSocket mServerSocket;
		private int svrPort = 6620;

		public ReceiveFileThread(int port) {
			svrPort = port;
		}

		@Override
		public void run() {
			while (autoRestart) {

				try {
					mServerSocket = new ServerSocket(svrPort);
					System.out.println("Receive Server started ...");

					while (mServerSocket != null && !mServerSocket.isClosed()) {
						Socket cilentSocket = mServerSocket.accept();
						cilentSocket.setSoTimeout(1500);
						new SaveFile2Disk(cilentSocket).start();
					}
				} catch (Exception ex) {
					System.out.println("Server shutdown. ->" + ex.getMessage());
				} finally {
					try {
						if (mServerSocket != null) {
							mServerSocket.close();
						}
					} catch (IOException ex) {
						// TODO Auto-generated catch block
						ex.printStackTrace();
					}
				}
			}
		}

		@Override
		public void start() {
			autoRestart = true;
			super.start();
		}

		public void release() {
			autoRestart = false;
			try {
				if (mServerSocket != null) {
					mServerSocket.close();
				}
			} catch (IOException ex) {
				// TODO Auto-generated catch block
				ex.printStackTrace();
			}

		}
	}

}
